﻿<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
	<head>
		<title>Plany - A google wave gadget for project planning</title>
	</head>
	<body>
	    <h1>Plany - A google wave gadget for project planning</h1>
	    <h2>Purpose</h2>
	    <p>Plany is a simple tool (i.e. a google wave gadget) for collaboratively creating a project plan and to keep track of project progress.
	    Plany can create some diagrams based on the information it has about the project.</p>	    
	    <p>To add plany to your wave, add <a href="http://secowela.googlecode.com/svn/trunk/Web/Gadget2/hello.xml" >http://secowela.googlecode.com/svn/trunk/Web/Gadget2/hello.xml</a> as a gadget.</p>
	    <h2>Technology</h2>
	    <p><b>Diagrams:</b> Plany uses the Google Chart API. The Gantt diagram is simply an abused bar chart.</p>
	    <p><b>Collaborative editing:</b> Plany is built on a small synchronization framework which in turn builds on the wave gadget API.
	    Each action you trigger is first encoded as an action object. Each action object has a unique key which is composed of a session ID and a scalar clock.
	    This key/value pair is then persisted via the wave API. Thus, eventually all participants will receive the same number of actions.
	    However, they may receive these actions in different order. For this purpose I use the scalar clock (lamport clock). It can happen that
	    two actions have the same clock. In this case we can still order them using the session ID. In the end this yields a total ordering of all actions.</p>	    
	    <p>The clock algorithm is straigt forward. When the gadget loads, it inspects all stored actions and searches for the highest clock value. This plus one
	    becomes the current clock for this session. With each new action the clock is increased by one. If the session receive an action from another user, it sets its
	    clock to <tt>session_clock := max(session_clock, action_clock+1)</tt>.</p>
	    <p>Still, different sessions can receive the actions in different order. In the end this means that a session can receive an action from the past.
	    The synchronization framework will then undo all actions up to the point where the received action fits in. Then it applies the received action and redos all
	    actions that have been undone before. It is possible that some action cannot be redone, for example it changed something that is now already deleted. In this case the
	    action is simply skipped. The nice thing about this approach is that you only have to implement the classical undo/redo pattern and that's it.
	    Furthermore, the UI is faster, because it applies incremental changes only. The brute force approach is to re-render the entire UI whenever the
	    wave API signals a state change. The solution presented here is better in this respect.</p>
	    <p>The framework uses optimistic synchronization, i.e. when a user triggers an action it is immediately applied and then communicated to others.
	    If some other user completed a conflicting action slightly faster then the other sessions will eventually find out. These session have to undo the applied actions,
	    apply the received one, and redo the undone actions. However, this happens only in rare cases of conflicting edits.
	    Thus, as long as there are no conflicts, the session will not have to undo anything. This results in a fast and responsive UI.</p>
	    <p>So much about the theory. I hope my implementation does the same :-). One problem is unsolved yet. Each new action increases the state size of the gadget.
	    At 100kb there is a cut off in Google Wave currently. I have not yet implemented means to throw away old actions and replace them with a snapshot of the gadget state.
	    However, for plany 100kb should be fair enough in the moment.</p>	    
	    <h2>Feedback</h2>
	    <p>Keep in mind that plany is an almost non-tested piece of software. If you break it, you own both parts :-)</p>
	    <p>However, bug reports and suggestions for improvements are always welcome. Contact me at torben.weis@googlewave.com</p>
	    <h2>Screenshots</h2>
	    <p><img src="shot1.png" /><br />Table view</p>
	    <p><img src="shot2.png" /><br />Chart view: Allocation of man months and gantt diagram</p>
	    <p></p>
	    <p>(c) Torben Weis, 2009; torben.weis@googlewave.com</p>
	</body>
</html>